package simpledb;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Iterator;

/**
 * Tuple maintains information about the contents of a tuple. Tuples have a
 * specified schema specified by a TupleDesc object and contain Field objects
 * with the data for each field.
 */
public class Tuple implements Serializable {

    private static final long serialVersionUID = 1L;

    private TupleDesc tupleDesc;

    private RecordId recordId;

    @Override
    public boolean equals(Object obj) {
        if (obj==this){
            return true;
        }
        if (obj instanceof Tuple){
            Tuple tuple=(Tuple) obj;
            if (!tuple.tupleDesc.equals(this.getTupleDesc())){
                return false;
            }
            if (!tuple.recordId.equals(this.recordId)){
                return false;
            }
            if (this.fieldArrayList.size()!=tuple.fieldArrayList.size()){
                return false;
            }
            for (int i = 0; i < this.fieldArrayList.size(); i++) {
                if (!this.fieldArrayList.get(i).equals(tuple.fieldArrayList.get(i))){
                    return false;
                }
            }
            return true;
        }
        return false;
    }

    private ArrayList<Field> fieldArrayList;

    /**
     * Create a new tuple with the specified schema (type).
     *
     * @param td the schema of this tuple. It must be a valid TupleDesc
     *           instance with at least one field.
     */
    public Tuple(TupleDesc td) {
        tupleDesc = td;
        fieldArrayList = new ArrayList<>(td.numFields());
        for (int i = 0; i < td.numFields(); i++) {
            fieldArrayList.add(null);
        }
        // some code goes here
    }

    /**
     * @return The TupleDesc representing the schema of this tuple.
     */
    public TupleDesc getTupleDesc() {
        // some code goes here
        return tupleDesc;
    }

    /**
     * @return The RecordId representing the location of this tuple on disk. May
     * be null.
     */
    public RecordId getRecordId() {
        // some code goes here
        return recordId;
    }

    /**
     * Set the RecordId information for this tuple.
     *
     * @param rid the new RecordId for this tuple.
     */
    public void setRecordId(RecordId rid) {
//        this.recordId = new RecordId(rid.getPageId(),rid.getTupleNumber());
        this.recordId=rid;
        // some code goes here
    }

    /**
     * Change the value of the ith field of this tuple.
     *
     * @param i index of the field to change. It must be a valid index.
     * @param f new value for the field.
     */
    public void setField(int i, Field f) {
        fieldArrayList.set(i, f);
        // some code goes here
    }

    /**
     * @param i field index to return. Must be a valid index.
     * @return the value of the ith field, or null if it has not been set.
     */
    public Field getField(int i) {
        // some code goes here
        return fieldArrayList.get(i);
    }

    /**
     * Returns the contents of this Tuple as a string. Note that to pass the
     * system tests, the format needs to be as follows:
     * <p>
     * column1\tcolumn2\tcolumn3\t...\tcolumnN
     * <p>
     * where \t is any whitespace (except a newline)
     */
    @Override
    public String toString() {
        // some code goes here
        String result = "";
        for (int i = 0; i < fieldArrayList.size() - 1; i++) {
            result = result + fieldArrayList.get(i).toString() + "\t";
        }
        result += fieldArrayList.get(fieldArrayList.size() - 1).toString();
        return result;
    }

    /**
     * @return An iterator which iterates over all the fields of this tuple
     */
    public Iterator<Field> fields() {
        // some code goes here
        return new Iterator<Field>() {
            private int cur=-1;

            @Override
            public boolean hasNext() {
                return cur!=fieldArrayList.size();
            }

            @Override
            public Field next() {
                cur++;
                return fieldArrayList.get(cur);
            }


        };
    }

    /**
     * reset the TupleDesc of this tuple (only affecting the TupleDesc)
     */
    public void resetTupleDesc(TupleDesc td) {
        // some code goes here
        tupleDesc=td;
    }
}
